import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import com.pluraprocessing.node.classloader.PluraClassLoader;

public class SimulatePostProcessingCode {

	private static final String POST_PROCESS_CLASS_NAME = "com.eightylegs.portal.PostProcess";
	private static final String POST_PROCESS_METHOD_NAME = "postProcess";
	private static final String POST_PROCESS_FINALIZE_METHOD_NAME = "finalize";

	public static void main(String[] args) {

		try {

			// run the test
			URL[] urls = new URL[1];
			Boolean[] load = new Boolean[1];
			String jarFile = "PostProcessing.jar";
			urls[0] = new SimulatePostProcessingCode().getClass().getResource(jarFile).toURI().toURL();
			load[0] = true;
			PluraClassLoader loader = new PluraClassLoader(urls, load);
			
			String filePath = "C:\\etc\\computationalcrawling\\downloadedResult\\";
			String returnedFileName = "File_Name.zip";
			
			if(returnedFileName.equals("File_Name.zip")) {
				System.err.println("Please provide the analysis zip file to be processed.");
				System.exit(1);
			}
			boolean done = postProcess(loader, filePath + returnedFileName, "tempPostProc" + returnedFileName, filePath);
			urls=null;
			load=null;

		} catch (Throwable e) {
			System.out.println(" Unrecoverable error: ");
			e.printStackTrace();
		}
	}

	public static final void copyInputStream(InputStream in, OutputStream out) throws IOException {
		byte[] buffer = new byte[1024];
		int len;

		while ((len = in.read(buffer)) >= 0)
			out.write(buffer, 0, len);

		in.close();
		out.close();
	}

	
	/**
	 * This method post processes the eightyLegs result file. It can handle a
	 * zip file or a .80 file. If the class loader is null, which can happen in
	 * case no post processing code exist for the Eighty App, then use default
	 * post processing.
	 * 
	 * @param classLoader
	 * @param runResultFile
	 * @param outFile
	 * @param filePath
	 * @throws EightyLegsAPIException
	 * @throws Exception
	 */
	private static boolean postProcess(PluraClassLoader classLoader, String runResultFile, String outFile, String filePath) throws Exception {
		try {
			String eightyFileTempLocation = null;
			ZipEntry entry = null;

			if (runResultFile.endsWith(".zip")) {

				ZipFile zipFile = new ZipFile(runResultFile);
				Enumeration entries = zipFile.entries();
				String dot80FilePath = "";
				while (entries.hasMoreElements()) {
					entry = (ZipEntry) entries.nextElement();
					if (!entry.isDirectory()) {// Directory is not expected
						String dot80FileName = entry.getName();
						// dot80FileName = dot80FileName.replaceAll("\\.80",
						// "");
						dot80FilePath = filePath + dot80FileName;
						copyInputStream(zipFile.getInputStream(entry), new BufferedOutputStream(new FileOutputStream(dot80FilePath)));
					}
				}
				zipFile.close();

				if (!entry.getName().endsWith(".80")) {
					return false;
				}
				eightyFileTempLocation = filePath + entry.getName();

			} else if (runResultFile.endsWith(".80")) {
				// this should not be the case, but just in case.
				eightyFileTempLocation = runResultFile;
			} else {
				throw new Exception("Invalid file type provided for post processing");
			}

			// read the temp .80 file
			BufferedInputStream temp80in = new BufferedInputStream(new FileInputStream(eightyFileTempLocation));
			CustomerResults customerResults = new CustomerResults();
			ZipOutputStream out = null;

			try {
				// read the temp .80 file
				File file = new File(filePath + outFile);
				out = new ZipOutputStream(new FileOutputStream(file));

				Class<?>[] argTypes = new Class<?>[4];
				argTypes[0] = int.class;
				argTypes[1] = String.class;
				argTypes[2] = byte[].class;
				argTypes[3] = ZipOutputStream.class;

				Object[] args = new Object[4];
				args[3] = out;

				customerResults.startRead(temp80in);
				String url;
				int count = 0;
				Boolean closeEntry = false;
				
				File zippedFile = new File(runResultFile);
				String[] resultFileInfo = zippedFile.getName().split(".zip");
				String fileNameWithoutExtension = "";
				if (resultFileInfo.length >= 1) {
					fileNameWithoutExtension = resultFileInfo[0];
				} else {
					fileNameWithoutExtension = "ProcessedResult";
				}

				long numberofLines = 0;
				while ((url = customerResults.readNextUrl(temp80in)) != null) {
					if (closeEntry) {
						out.closeEntry();
					}
					args[0] = count;
					args[1] = url;
					args[2] = customerResults.readNextData(temp80in);

					// if no post processing code provided
					if (classLoader == null) {
						if (count == 0) {
							out.putNextEntry(new ZipEntry(fileNameWithoutExtension + ".txt"));
						}

						out.write(url.getBytes());
						out.write(" ".getBytes());
						out.write((byte[]) args[2]);
						out.write("\r\n".getBytes());
					} else {
						if (count == 0) {

							Object[] startArgs = new Object[5];
							startArgs[0] = count;
							startArgs[1] = url;
							startArgs[2] = args[2];
							startArgs[3] = out;
							startArgs[4] = fileNameWithoutExtension;
							
							Class<?>[] startArgTypes = new Class<?>[5];
							startArgTypes[0] = int.class;
							startArgTypes[1] = String.class;
							startArgTypes[2] = byte[].class;
							startArgTypes[3] = ZipOutputStream.class;
							startArgTypes[4] = String.class;
						

							try {
								closeEntry = (Boolean) classLoader.loadClass(POST_PROCESS_CLASS_NAME).getMethod(POST_PROCESS_METHOD_NAME,
										startArgTypes).invoke(null, startArgs);
							} catch (NoSuchMethodException ex) {
								closeEntry = (Boolean) classLoader.loadClass(POST_PROCESS_CLASS_NAME).getMethod(POST_PROCESS_METHOD_NAME, argTypes)
										.invoke(null, args);
								out.flush();
							}

						} else {
							closeEntry = (Boolean) classLoader.loadClass(POST_PROCESS_CLASS_NAME).getMethod(POST_PROCESS_METHOD_NAME, argTypes)
									.invoke(null, args);
						}
						if(closeEntry == false) {
							numberofLines++;
						}
					}

					count++;
				}
				

				closeEntry = false;
				if (!closeEntry) {
					Class<?>[] finalArgTypes = new Class<?>[2];
					finalArgTypes[0] = int.class;
					finalArgTypes[1] = ZipOutputStream.class;

					Object[] finalArgs = new Object[2];
					finalArgs[1] = out;
					finalArgs[0] = count;
					try {
						closeEntry = (Boolean) classLoader.loadClass(POST_PROCESS_CLASS_NAME).getMethod(POST_PROCESS_FINALIZE_METHOD_NAME,
								finalArgTypes).invoke(null, finalArgs);
					} catch (NoSuchMethodException ex) {
						// ignore since not all post processing jars have a
						// finalize method.
					}
				}
				if (count > 0) {
					out.closeEntry();
				}

			} finally {

				temp80in.close();

				if (out != null) {
					out.close();
					out = null;
				}

			}
		}

		catch (Exception e) {
			e.printStackTrace();
			throw new Exception("Error post processing result file.");
		}

		return true;
	}

}
